<script setup>
import { ref, watch, onBeforeUnmount, nextTick } from 'vue';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { getDiagnosticService } from '../services/diagnosticService';

const props = defineProps({
  content: { type: String, default: '' },
  originalContent: { type: String, default: '' },
  useDiff: { type: Boolean, default: false },
  ext: { type: String, default: '' },
  isActive: { type: Boolean, default: true },
  theme: { type: String, default: 'vs-dark' },
  // 单编辑器选项
  editorOptions: { type: Object, default: () => ({}) },
  // Diff 编辑器专属选项（如 renderSideBySide、ignoreTrimWhitespace、originalEditable 等）
  diffEditorOptions: { type: Object, default: () => ({}) }
});

const emit = defineEmits(['editor-ready', 'content-change', 'cursor-change', 'diff-updated', 'accept-change', 'reject-change']);

// 编辑器容器
const editorContainer = ref(null);

// 编辑器与模型（单）
let editor = null;
let editorModel = null;
// Diff 编辑器与模型
let diffEditor = null;
let originalModel = null;
let modifiedModel = null;

// 可释放对象
const disposables = [];
// 标志：是否正在程序化设置内容（避免触发不必要的content-change事件）
let isSettingContent = false;

// 变更装饰器和控制
let changeDecorations = [];
let changeWidgets = [];

// 从扩展名推断语言
const getLanguageFromExtension = (ext) => {
  const langMap = {
    'js': 'javascript', 'ts': 'typescript', 'jsx': 'javascript', 'tsx': 'typescript',
    'vue': 'vue', 'html': 'html', 'css': 'css', 'scss': 'scss', 'sass': 'scss', 'less': 'less',
    'json': 'json', 'jsonl': 'json', 'md': 'markdown', 'py': 'python', 'java': 'java',
    'cpp': 'cpp', 'c': 'c', 'cs': 'csharp', 'php': 'php', 'rb': 'ruby', 'go': 'go',
    'rs': 'rust', 'xml': 'xml', 'yaml': 'yaml', 'yml': 'yaml', 'sh': 'shell', 'sql': 'sql'
  };
  return langMap[ext?.toLowerCase()] || 'plaintext';
};

// 创建变更装饰器（鲁棒处理删除场景：modified* 为 0 时在 modified 端选择最近的有效行）
const createChangeDecorations = (changes) => {
  if (!changes || !Array.isArray(changes)) return [];
  try {
    const modifiedEditor = diffEditor?.getModifiedEditor?.();
    const model = modifiedEditor?.getModel?.();
    const lineCount = model?.getLineCount?.() || 1;

    const clamp = (n) => Math.min(Math.max(1, Number(n) || 1), lineCount);

    return changes.map(change => {
      // 识别变更类型
      const changeType = change.originalEndLineNumber === 0 ? 'added' :
                        change.modifiedEndLineNumber === 0 ? 'deleted' : 'modified';

      // 兼容删除：modifiedStartLineNumber 可能为 0
      let start = Number(change.modifiedStartLineNumber || 0);
      let end = Number(change.modifiedEndLineNumber || 0);

      if (start <= 0 && end <= 0) {
        // 纯删除且 modified 端无行，锚定到删除块前后最近的一行
        // 优先使用 originalStartLineNumber 的下一行作为锚点
        const anchor = clamp((change.originalStartLineNumber || 1));
        start = anchor; end = anchor;
      } else {
        // 常规场景：夹紧到合法范围
        start = clamp(start > 0 ? start : (end > 0 ? end : 1));
        end = clamp(end > 0 ? end : start);
      }

      return {
        range: new monaco.Range(start, 1, end, 1),
        options: {
          isWholeLine: true,
          className: `monaco-diff-${changeType}`,
          glyphMarginClassName: `monaco-diff-glyph-${changeType}`,
          linesDecorationsClassName: `monaco-diff-line-${changeType}`,
          marginClassName: `monaco-diff-margin-${changeType}`
        }
      };
    });
  } catch (e) {
    console.warn('[MonacoEditor] createChangeDecorations error:', e);
    return [];
  }
};

// 创建接受/拒绝控制按钮（鲁棒处理删除场景）
const createChangeWidgets = (changes) => {
  if (!changes || !Array.isArray(changes) || !diffEditor) return [];
  const modifiedEditor = diffEditor.getModifiedEditor();
  const model = modifiedEditor?.getModel?.();
  const lineCount = model?.getLineCount?.() || 1;
  const clamp = (n) => Math.min(Math.max(1, Number(n) || 1), lineCount);

  const widgets = [];
  changes.forEach((change, index) => {
    const rawStart = Number(change.modifiedStartLineNumber || 0);
    const rawEnd = Number(change.modifiedEndLineNumber || 0);
    const safeLine = clamp(rawStart > 0 ? rawStart : (rawEnd > 0 ? rawEnd : (change.originalStartLineNumber || 1)));

    const widget = {
      domNode: null,
      getId: () => `change-widget-${index}`,
      getDomNode: () => {
        if (!widget.domNode) {
          const container = document.createElement('div');
          container.className = 'monaco-change-widget';
          container.innerHTML = `
            <div class="change-controls">
              <button class="accept-btn" data-change-index="${index}" title="接受此变更">
                <svg width="12" height="12" viewBox="0 0 12 12">
                  <path d="M10 3L4.5 8.5L2 6" stroke="currentColor" stroke-width="2" fill="none"/>
                </svg>
              </button>
              <button class="reject-btn" data-change-index="${index}" title="拒绝此变更">
                <svg width="12" height="12" viewBox="0 0 12 12">
                  <path d="M9 3L3 9M3 3l6 6" stroke="currentColor" stroke-width="2" fill="none"/>
                </svg>
              </button>
            </div>
          `;

          // 添加事件监听
          container.querySelector('.accept-btn').addEventListener('click', () => {
            emit('accept-change', { change, index });
          });
          container.querySelector('.reject-btn').addEventListener('click', () => {
            emit('reject-change', { change, index });
          });

          widget.domNode = container;
        }
        return widget.domNode;
      },
      getPosition: () => ({
        position: { lineNumber: safeLine, column: 1 },
        preference: [monaco.editor.ContentWidgetPositionPreference.ABOVE]
      })
    };

    widgets.push(widget);
  });

  return widgets;
};

// 应用变更装饰器和控件（原子替换，避免异常导致高亮被清空）
const applyChangeDecorations = (changes) => {
  if (!diffEditor || !props.useDiff) return;
  const modifiedEditor = diffEditor.getModifiedEditor();

  try {
    // 先计算新的装饰器集合
    const newDecorations = createChangeDecorations(changes);
    // 使用 deltaDecorations 以旧换新，避免先清空产生的闪烁或异常后的空白
    changeDecorations = modifiedEditor.deltaDecorations(changeDecorations, newDecorations);
  } catch (e) {
    console.warn('[MonacoEditor] applyChangeDecorations error:', e);
  }

  // 替换控制按钮（仅在内联模式下）
  try {
    const inlineMode = !props.diffEditorOptions?.renderSideBySide;
    // 先移除旧控件
    if (changeWidgets.length) {
      changeWidgets.forEach(widget => {
        try { modifiedEditor.removeContentWidget(widget); } catch {}
      });
      changeWidgets = [];
    }
    if (inlineMode) {
      const widgets = createChangeWidgets(changes);
      widgets.forEach(widget => {
        try { modifiedEditor.addContentWidget(widget); } catch {}
        changeWidgets.push(widget);
      });
    }
  } catch (e) {
    console.warn('[MonacoEditor] applyChangeWidgets error:', e);
  }
};

// 清除变更装饰器和控件
const clearChangeDecorations = () => {
  if (diffEditor) {
    const modifiedEditor = diffEditor.getModifiedEditor();

    // 清除装饰器
    if (changeDecorations.length > 0) {
      try { modifiedEditor.deltaDecorations(changeDecorations, []); } catch {}
      changeDecorations = [];
    }

    // 清除控件
    changeWidgets.forEach(widget => {
      try { modifiedEditor.removeContentWidget(widget); } catch {}
    });
    changeWidgets = [];
  }
};

// 初始化编辑器
const initializeEditor = async () => {
  if (!editorContainer.value || !props.isActive) return;
  try {
    const language = getLanguageFromExtension(props.ext);
    console.log('[MonacoEditor] Initializing editor - useDiff:', props.useDiff, 'isActive:', props.isActive, 'ext:', props.ext);

    if (props.useDiff) {
      diffEditor = monaco.editor.createDiffEditor(editorContainer.value, {
        theme: props.theme,
        automaticLayout: true,
        renderSideBySide: true,
        ...props.diffEditorOptions,
      });

      isSettingContent = true;
      originalModel = monaco.editor.createModel(props.originalContent || '', language);
      modifiedModel = monaco.editor.createModel(props.content || '', language);
      diffEditor.setModel({ original: originalModel, modified: modifiedModel });
      isSettingContent = false;

      const changeDisposable = modifiedModel.onDidChangeContent(() => {
        console.log('[MonacoEditor] modifiedModel content changed, isSettingContent:', isSettingContent);
        if (!isSettingContent) {
          const newContent = modifiedModel.getValue();
          console.log('[MonacoEditor] Emitting content-change event, content length:', newContent.length);
          emit('content-change', newContent);
          // 触发诊断更新
          try {
            getDiagnosticService().collectProblems();
          } catch (error) {
            console.warn('Failed to update diagnostics:', error);
          }
        } else {
          console.log('[MonacoEditor] Skipping content-change event due to isSettingContent flag');
        }
      });
      disposables.push(changeDisposable);

      const cursorDisposable = diffEditor.getModifiedEditor().onDidChangeCursorPosition((e) => {
        emit('cursor-change', e.position);
      });
      disposables.push(cursorDisposable);

      // 监听 diff 变化
      const diffDisposable = diffEditor.onDidUpdateDiff(() => {
        try { 
          const changes = diffEditor.getLineChanges?.() || [];
          emit('diff-updated', changes);
          // 应用变更装饰器
          applyChangeDecorations(changes);
        } catch {}
      });
      disposables.push(diffDisposable);

      emit('editor-ready', {
        editor: diffEditor,
        originalEditor: diffEditor.getOriginalEditor(),
        modifiedEditor: diffEditor.getModifiedEditor(),
        model: { original: originalModel, modified: modifiedModel }
      });
    } else {
      editor = monaco.editor.create(editorContainer.value, {
        theme: props.theme,
        automaticLayout: true,
        ...props.editorOptions,
      });

      isSettingContent = true;
      editorModel = monaco.editor.createModel(props.content || '', language);
      editor.setModel(editorModel);
      isSettingContent = false;

      const changeDisposable = editorModel.onDidChangeContent(() => {
        console.log('[MonacoEditor] editorModel content changed, isSettingContent:', isSettingContent);
        if (!isSettingContent) {
          const newContent = editorModel.getValue();
          console.log('[MonacoEditor] Emitting content-change event, content length:', newContent.length);
          emit('content-change', newContent);
          // 触发诊断更新
          try {
            getDiagnosticService().collectProblems();
          } catch (error) {
            console.warn('Failed to update diagnostics:', error);
          }
        } else {
          console.log('[MonacoEditor] Skipping content-change event due to isSettingContent flag');
        }
      });
      disposables.push(changeDisposable);

      const cursorDisposable = editor.onDidChangeCursorPosition((e) => {
        emit('cursor-change', e.position);
      });
      disposables.push(cursorDisposable);

      emit('editor-ready', { editor, model: editorModel });
    }
  } catch (error) {
    console.error('[MonacoEditor] 初始化失败:', error);
  }
};

// 清理
const cleanup = () => {
  // 清除变更装饰器和控件
  clearChangeDecorations();
  
  try {
    for (const d of disposables) {
      try { d.dispose?.(); } catch {}
    }
  } finally {
    disposables.length = 0;
  }
  if (editorModel) { try { editorModel.dispose(); } catch {} editorModel = null; }
  if (editor) { try { editor.dispose(); } catch {} editor = null; }
  if (originalModel) { try { originalModel.dispose(); } catch {} originalModel = null; }
  if (modifiedModel) { try { modifiedModel.dispose(); } catch {} modifiedModel = null; }
  if (diffEditor) { try { diffEditor.dispose(); } catch {} diffEditor = null; }
};

// 活动状态变化时初始化/清理
watch(() => props.isActive, async (active, oldActive) => {
  console.log('[MonacoEditor] isActive changed from', oldActive, 'to', active);
  if (active) {
    console.log('[MonacoEditor] Activating editor, calling initializeEditor');
    await nextTick();
    await initializeEditor();
    // 同步初始内容
    if (props.useDiff) {
      if (modifiedModel && typeof props.content === 'string') {
        const cur = modifiedModel.getValue();
        if (cur !== props.content) {
          isSettingContent = true;
          modifiedModel.setValue(props.content);
          isSettingContent = false;
        }
      }
      if (originalModel && typeof props.originalContent === 'string') {
        const curO = originalModel.getValue();
        if (curO !== props.originalContent) {
          isSettingContent = true;
          originalModel.setValue(props.originalContent);
          isSettingContent = false;
        }
      }
    } else if (editorModel && typeof props.content === 'string') {
      const cur = editorModel.getValue();
      if (cur !== props.content) {
        isSettingContent = true;
        editorModel.setValue(props.content);
        isSettingContent = false;
      }
    }
  } else {
    console.log('[MonacoEditor] Deactivating editor, calling cleanup');
    cleanup();
  }
}, { immediate: true });

// 同步外部内容（modified）
watch(() => props.content, (newContent) => {
  if (props.useDiff) {
    if (modifiedModel && typeof newContent === 'string') {
      const current = modifiedModel.getValue();
      if (current !== newContent) {
        isSettingContent = true;
        modifiedModel.setValue(newContent);
        isSettingContent = false;
      }
    }
  } else if (editorModel && typeof newContent === 'string') {
    const current = editorModel.getValue();
    if (current !== newContent) {
      isSettingContent = true;
      editorModel.setValue(newContent);
      isSettingContent = false;
    }
  }
});

// 同步原始内容（original）
watch(() => props.originalContent, (newOriginal) => {
  if (props.useDiff && originalModel && typeof newOriginal === 'string') {
    const current = originalModel.getValue();
    if (current !== newOriginal) {
      isSettingContent = true;
      originalModel.setValue(newOriginal);
      isSettingContent = false;
    }
  }
});

// 语言变化
watch(() => props.ext, (newExt, oldExt) => {
  const lang = getLanguageFromExtension(newExt);
  if (props.useDiff) {
    if (originalModel) monaco.editor.setModelLanguage(originalModel, lang);
    if (modifiedModel) monaco.editor.setModelLanguage(modifiedModel, lang);
  } else if (editorModel && newExt !== oldExt) {
    monaco.editor.setModelLanguage(editorModel, lang);
  }
});

// 主题变化
watch(() => props.theme, (newTheme, oldTheme) => {
  if (newTheme !== oldTheme) {
    monaco.editor.setTheme(newTheme);
  }
});

// 选项变化
watch(() => props.editorOptions, (opts) => { try { editor?.updateOptions?.(opts || {}); } catch {} }, { deep: true });
watch(() => props.diffEditorOptions, (opts) => { try { diffEditor?.updateOptions?.(opts || {}); } catch {} }, { deep: true });

onBeforeUnmount(() => cleanup());

// 方法暴露
function updateContent(val) {
  if (props.useDiff) {
    if (modifiedModel && typeof val === 'string') {
      const current = modifiedModel.getValue();
      if (current !== val) {
        isSettingContent = true;
        modifiedModel.setValue(val);
        isSettingContent = false;
      }
    }
  } else if (editorModel && typeof val === 'string') {
    const current = editorModel.getValue();
    if (current !== val) {
      isSettingContent = true;
      editorModel.setValue(val);
      isSettingContent = false;
    }
  }
}

defineExpose({
  updateContent,
  getEditor: () => props.useDiff
    ? { original: diffEditor?.getOriginalEditor?.(), modified: diffEditor?.getModifiedEditor?.(), diffEditor }
    : editor,
  getModel: () => props.useDiff
    ? { original: originalModel, modified: modifiedModel }
    : editorModel,
});
</script>

<template>
  <div class="w-full h-full">
    <div ref="editorContainer" class="w-full h-full"></div>
  </div>
</template>

<style>
/* Monaco Editor 内联 Diff 样式 */
.monaco-diff-added {
  background-color: rgba(46, 160, 67, 0.15) !important;
}

.monaco-diff-modified {
  background-color: rgba(255, 193, 7, 0.15) !important;
}

.monaco-diff-deleted {
  background-color: rgba(248, 81, 73, 0.15) !important;
}

.monaco-diff-glyph-added::before {
  content: '+';
  color: #2ea043;
  font-weight: bold;
}

.monaco-diff-glyph-modified::before {
  content: '~';
  color: #fb8500;
  font-weight: bold;
}

.monaco-diff-glyph-deleted::before {
  content: '-';
  color: #f85149;
  font-weight: bold;
}

.monaco-diff-line-added {
  border-left: 3px solid #2ea043 !important;
}

.monaco-diff-line-modified {
  border-left: 3px solid #fb8500 !important;
}

.monaco-diff-line-deleted {
  border-left: 3px solid #f85149 !important;
}

/* 变更控制按钮样式 */
.monaco-change-widget {
  position: relative;
  z-index: 10;
}

.change-controls {
  display: flex;
  gap: 4px;
  padding: 2px;
  background: var(--vscode-editor-background, #1e1e1e);
  border: 1px solid var(--vscode-widget-border, #454545);
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

.change-controls button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 2px;
  cursor: pointer;
  transition: all 0.2s ease;
  background: transparent;
}

.accept-btn {
  color: #2ea043;
}

.accept-btn:hover {
  background: rgba(46, 160, 67, 0.2);
}

.reject-btn {
  color: #f85149;
}

.reject-btn:hover {
  background: rgba(248, 81, 73, 0.2);
}

.change-controls button:active {
  transform: scale(0.95);
}

/* 暗色主题适配 */
.vs-dark .change-controls {
  background: #2d2d30;
  border-color: #3e3e42;
}

/* 亮色主题适配 */
.vs .change-controls {
  background: #ffffff;
  border-color: #c8c8c8;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>